﻿import jwt
import time

from django.conf import settings

from rest_framework.authentication import BaseAuthentication, get_authorization_header #问题 这几个模块是干什么的呢？
from rest_framework import exceptions
from jwt.exceptions import ExpiredSignatureError

# 导入用户信息
from .models import OAUser

# 断点测试
import pdb

def generate_jwt(user):

    timestamp = time.time() + 60 * 60 * 24 * 7  # Token 7天过期
    token = jwt.encode({"userid": user.pk, "exp": timestamp}, settings.SECRET_KEY)
    # exp是一个特殊的参数，用以表示Token过期的时间
    return token

class UserTokenAuthentication(BaseAuthentication):
    def authenticate(self, request):
        # 这里的request：是rest_framework.request.Request对象
        return request._request.user, request._request.auth

class JWTAuthentication(BaseAuthentication):
    """
    Authorization: JWT 401f7ac837da42b97f613d789819ff93537bee6a
    """
    keyword = 'jwt'
    model = None

    def authenticate(self, request):
        # 从请求头中获取Authorization
        # 把Authorization字段切割成两段(以空格为分隔符，按理存在两个字段：["JWT", "401f7ac837da42b97f613d789819ff93537bee6a"]
        auth = get_authorization_header(request).split()

        # auth字段为空｜或者auth的第一个字段(按理是JWT)不等于JWT的小写形式，那么则认为没有返回JWT，系统则返回NONE
        if not auth or auth[0].lower() != self.keyword.lower().encode():
            print(auth)
            return None

        if len(auth) == 1:  # 只分割出1个内容，不对！
            msg = ('没有提供JWT Token!')
            raise exceptions.AuthenticationFailed(msg)
        elif len(auth) > 2:  # 分割出>2个内容，说明存在多个空格。JWT格式错误
            msg = ('JWT Token不可用!应该提供一个空格。')
            raise exceptions.AuthenticationFailed(msg)

        try:
            jwt_token = auth[1] # 获取JWT的实际Token字符串

            jwt_info = jwt.decode(jwt_token, settings.SECRET_KEY, algorithms="HS256") # 对JWT的Token进行解码。如果在解码的时候，/
                            # 发现有"exp"字段(请参照函数"generate_jwt"中的jwt.encode)，而且exp已经过期，则会报错ExpiredSignatureError(参考下方except部分)

            userid = jwt_info.get('userid')  # JWT被解码成功后(应该是一个对象)、获取其中的useid #问题(为啥需要用get)

            try:  # 对所提取出来的userid进行验证
                user = OAUser.objects.get(pk=userid)  # 使用ORM进行查询，如果成功的话，将可以得到用户信息
                return (user, None)  # 返回元组：用户信息 + None
            except:  # 如果没有查询到此用户
                msg = "用户不存在!"
                raise exceptions.AuthenticationFailed(msg)

        except jwt.ExpiredSignatureError:
            msg = ('Token已经过期！')
            raise exceptions.AuthenticationFailed(msg)

